/*
 * Copyright (c) 2017-2019 Vered Information Technology Corp.,Ltd. All rights reserved. 蔷薇信息技术有限公司版权所有.
 */
package com.chao.aspect;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.skywalking.apm.toolkit.trace.ActiveSpan;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;

/**
 * 控制层（controller）入参及返回值记录
 */
@Component
@Aspect
@Slf4j
public class LoggerAspect {

    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)" +
            " || @annotation(org.springframework.web.bind.annotation.GetMapping)" +
            " || @annotation(org.springframework.web.bind.annotation.PostMapping)" +
            " || @annotation(org.springframework.web.bind.annotation.PutMapping)" +
            " || @annotation(org.springframework.web.bind.annotation.DeleteMapping)")
    public void pointcut() {
    }

    @Around("pointcut()")
    public Object recordRequestLog(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                .getRequest();

        log.info("请求信息，url：{}, 入参: {}", request.getRequestURL().toString(),
                getRequestParams(joinPoint, request));
        ActiveSpan.info(String.format("请求信息，url：%s, 入参: %s", request.getRequestURL().toString(),
                getRequestParams(joinPoint, request)));
        Object result = joinPoint.proceed();
        log.info("返回数据：{}", JSONObject.toJSONString(result));
        ActiveSpan.info(String.format("返回数据：%s", JSONObject.toJSONString(result)));

        return result;
    }

    /**
     * 获取请求入参信息，兼容各种请求类型
     *
     * @param point
     * @param request
     * @return
     */
    private String getRequestParams(ProceedingJoinPoint point, HttpServletRequest request) {
        String contentType = request.getContentType();
        if (!StringUtils.isEmpty(contentType) && contentType.toLowerCase().startsWith(MediaType.APPLICATION_JSON_VALUE)) {
            MethodSignature signature = (MethodSignature) point.getSignature();
            Annotation[][] parameterAnnotations = signature.getMethod().getParameterAnnotations();
            for (Annotation[] parameterAnnotation : parameterAnnotations) {
                int paramIndex = ArrayUtils.indexOf(parameterAnnotations, parameterAnnotation);
                for (Annotation annotation : parameterAnnotation) {
                    if (annotation instanceof RequestBody) {
                        return JSONObject.toJSONString(point.getArgs()[paramIndex]);
                    }
                }
            }
        } else {
            return JSONObject.toJSONString(request.getParameterMap());
        }
        return null;
    }
}
